Angular Reactive Forms
In this tutorial, lets see how to use ReactiveForms
in Angular to create a form to get use input and validate the form.
The terms that are used in Reactive forms are listed below.
- FormControl
- FormGroup
- FormArray
- FormBuilder
- Validators
FormControl
FormControl
is used to track the value and validation status of the individual form control.
FormGroup
FormGroup
is used to track the value and status for the collection of form controls.
FormArray
FormArray
is used to track the value and status for the array of form controls.
FormBuilder
FormBuilder
provides to create instances of a FormControl
, FormGroup
, or FormArray
. It reduces the amount of boilerplate needed to build complex forms.
Validators
The Validators
are used to apply validations to the form controls.
Create an angular application
First, lets create an application using angular cli command.
ng new reactive-forms-tutorial
This will create a brand new angular application.
Add ReactiveFormsModule to to application
Next open the app.module.ts file and import the ReactiveFormsModule
from @angular/forms
and add it to the imports array of @NgModule
decorator.
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { ReactiveFormsModule } from "@angular/forms";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, AppRoutingModule, ReactiveFormsModule],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
Without importing ReactiveFormsModule
we cannot use the Reactive forms in our application.
Create EmployeeComponent to setup ReactiveForm
Create a new component EmployeeComponent
with the following command.
ng g c employee
This will create an angular component in employee folder. Now open the employee.component.ts
file and modify the code as below.
import { Component, OnInit } from "@angular/core";
import {
FormGroup,
FormBuilder,
FormControl,
FormArray,
Validators
} from "@angular/forms";
@Component({
selector: "app-employee",
templateUrl: "./employee.component.html",
styleUrls: ["./employee.component.css"]
})
export class EmployeeComponent implements OnInit {
employeeForm: FormGroup;
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
this.employeeForm = this.formBuilder.group({
employeeName: ["", Validators.required],
designation: ["", Validators.required],
gender: ["--Select--", Validators.required],
address: ["", Validators.required],
skills: this.formBuilder.array([new FormControl("", Validators.required)])
});
}
addSkills() {
const items = this.employeeForm.get("skills") as FormArray;
items.push(new FormControl("", Validators.required));
}
onSubmit() {
if (this.employeeForm.valid) {
alert("Form submitted successfully.");
}
}
}
In the above code we have imported FormGroup
, FormBuilder
, FormControl
, FormArray
and Validators
from @angular/forms
inorder to use reactive forms.
Next, inject the FormBuilder
to the constructor with a private variable named formBuilder. This is used to create FormGroup
or FormArray
in an easy way. We need to create a FormGroup
to hold, group of FormControl
's to get the employee details. Lets name the variable with the name employeeForm
.
Next, in the ngOnInit()
life cycle we shall create a FormGroup
using FormBuilder
object. The FormGroup
will contain FormControl
's like employeeName
, designation
, gender
and address
and a FormArray
with the name skills
.
We can add any number of skills to an employee, so that's why we have declare it as FormArray
with initially one FormControl
. In the sense,by default it will add one skill.
The addSkills()
function is used to add a FormControl to the skills FormArray.
The onSubmit()
function will open an alert
box if the employeeForm
is free of validation error.
Setting validation to FormContol
The validation is applied to the FormControl
by means of Validators
class.
Example, the FormControl for employeeName
is represented as
["", Validators.required]
The ""
represents the default value to the FormControl
and Validators.required
represents the required
validator assigned to the FormControl
.
Setting the html template of EmployeeComponent for ReactiveForm
Now looking to the employee.component.html
file.
<div class="container">
<form [formGroup]="employeeForm">
<div class="form-group">
<label for="employeeName">Employee Name</label>
<input type="text" class="form-control" placeholder="Employee Name" formControlName="employeeName" />
<span *ngIf="
!employeeForm.get('employeeName').valid &&
employeeForm.get('employeeName').touched &&
employeeForm.get('employeeName').errors.required
">
Name is required!
</span>
</div>
<div class="form-group">
<label for="designation">Designation</label>
<input type="text" class="form-control" placeholder="Designation" formControlName="designation" />
<span *ngIf="
!employeeForm.get('designation').valid &&
employeeForm.get('designation').touched &&
employeeForm.get('designation').errors.required
">
Designation is required!
</span>
</div>
<div class="form-group">
<label for="gender">Gender</label>
<select formControlName="gender" class="form-control">
<option>--Select--</option>
<option value="male">Male</option>
<option value="female">Female</option>
</select>
<span *ngIf="
!employeeForm.get('gender').valid &&
employeeForm.get('gender').touched &&
employeeForm.get('gender').errors.required
">
Gender is required!
</span>
</div>
<div class="form-group">
<label for="address">Address</label>
<input type="text" class="form-control" placeholder="Address" formControlName="address" />
<span *ngIf="
!employeeForm.get('address').valid &&
employeeForm.get('address').touched &&
employeeForm.get('address').errors.required
">
Address is required!
</span>
</div>
<div formArrayName="skills">
<ng-container *ngFor="let skill of employeeForm.get('skills').controls; let i = index">
<div class="form-group">
<label for="skills">Skills {{ i + 1 }}</label>
<input type="text" [formControlName]="i" class="form-control" />
<span *ngIf="
!employeeForm.get('skills')['controls'][i].valid &&
employeeForm.get('skills')['controls'][i].touched &&
employeeForm.get('skills')['controls'][i].errors.required">
Skill is required!
</span>
</div>
</ng-container>
</div>
<button type="submit" class="btn btn-primary" (click)="onSubmit()">
Submit
</button>
<button class="btn btn-danger" (click)="addSkills()">Add Skill</button>
</form>
</div>
In the employee.component.html
file, we initially set the formGroup
to employeeForm
in form tag.
For each input controls, we give a name of the FormControl
in formControlName
.
The *ngIf directive is used to check for any validation error for the FormControl by checked whether the FormControl
is valid or not and check whether it has been touched and whether required
error is in errors object of the FormControl
.
The skills
is a FormArray
, so we loop through the controls in the FormArray
using ngFor
directive and assign the index position of the FormControl
as the name to formControlName
.
Clicking on submit
button will call the onSubmit()
function, which in turns, checks whether the form is valid or not and displays an
Run the app using
ng serve --o
Output with validation error.
Output with success alert message.